/**
 * Software License, Version 1.0 Copyright 2003 The Trustees of Indiana
 * University. All rights reserved. Redistribution and use in source and binary
 * forms, with or without modification, are permitted provided that the
 * following conditions are met: 1) All redistributions of source code must
 * retain the above copyright notice, the list of authors in the original source
 * code, this list of conditions and the disclaimer listed in this license; 2)
 * All redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the disclaimer listed in this license in the
 * documentation and/or other materials provided with the distribution; 3) Any
 * documentation included with all redistributions must include the following
 * acknowledgement: "This product includes software developed by the Community
 * Grids Lab. For further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/." Alternatively, this acknowledgement may
 * appear in the software itself, and wherever such third-party acknowledgments
 * normally appear. 4) The name Indiana University or Community Grids Lab or
 * NaradaBrokering, shall not be used to endorse or promote products derived
 * from this software without prior written permission from Indiana University.
 * For written permission, please contact the Advanced Research and Technology
 * Institute ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202. 5)
 * Products derived from this software may not be called NaradaBrokering, nor
 * may Indiana University or Community Grids Lab or NaradaBrokering appear in
 * their name, without prior written permission of ARTI. Indiana University
 * provides no reassurances that the source code provided does not infringe the
 * patent or any other intellectual property rights of any other entity. Indiana
 * University disclaims any liability to any recipient for claims brought by any
 * other entity based on infringement of intellectual property rights or
 * otherwise. LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH
 * NO WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY
 * GIVES NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 * GENERATED USING SOFTWARE.
 */
package cgl.narada.service.security.securityprovider;

import java.io.File;

import org.apache.log4j.Logger;

/**
 * This is a temporary placeholder class for acting as a root security provider !
 * <br>
 * Created on Apr 13, 2005
 * 
 * @author Harshawardhan Gadgil (hgadgil@grids.ucs.indiana.edu)
 */

public class ROOTSecurityProvider {

    static Logger log = Logger.getLogger("ROOTSecurityProvider");

    /**
     * Generates NEW ROOT certificate for use of this ROOT Provider. If used,
     * then need to resign all public keys of the entities that were issued the
     * certificates from the Root provider. By default the validity is set to 1
     * year (365 days)
     */
    public static void GenerateROOTCertificate(CertificateManager certMan) {

        String rootDN = "CN=ROOTProvider,OU=Community Grids Lab,"
                + "O=Indiana University,L=Bloomington,S=IN," + "C=U.S.A.";

        KeyToolFacade
                .GenerateKey(certMan, certMan.ROOT_CA_ALIAS, rootDN, "365");
        KeyToolFacade.GenerateSelfCertifiedCertificate(certMan,
                certMan.ROOT_CA_ALIAS, rootDN, "365");
        // CertificateUtil.saveCertsToFile(certMan, certMan.ROOT_CA_ALIAS,
        // certMan.ROOT_CA_CERTIFICATE, certMan.ROOT_CA_PRIVATEKEY);
    }

    /**
     * Issues a new digitally signed certificate. This certificate is signed by
     * the ROOT Provider's private key.
     * 
     * @param certMan
     * @param entityName -
     *            The name of the entity for which the certificate is to be
     *            issued. This will also be the alias of the entity in the
     *            keystore. Make sure these are unique for different entities
     * @param DNAME -
     *            The complete Distinguished Name of the entity. If null, a
     *            default is used <code>CN=entityName,OU=Community Grids
     *            Lab,O=Indiana University,L=Bloomington,C=US</code>
     * @param validityDays -
     *            The number of days for which this certificate is valid
     */
    public static void IssueSignedCertificate(CertificateManager certMan,
            String entityName, String DNAME, String validityDays) {

        if (DNAME == null)
            DNAME = "\"CN="
                    + entityName
                    + ",OU=Community Grids Lab,O=Indiana University,L=Bloomington,C=US\"";
        else {
            // if (!DNAME.startsWith("\""))
            // DNAME = "\"" + DNAME;
            // if (!DNAME.endsWith("\""))
            // DNAME = DNAME + "\"";
        }

        KeyToolFacade.GenerateKey(certMan, entityName, DNAME, validityDays);

        // Now Save the keys to files
        // Default file names: clientID.cer, clientID.key

        CertificateUtil.saveCertsToFile(certMan, entityName,
                certMan.KEYSTORE_PATH + "/" + entityName + ".cer",
                certMan.KEYSTORE_PATH + "/" + entityName + ".key");

        // Generate Certificate Sign Request
        String csr = KeyToolFacade.GenerateCertificateRequest(certMan,
                entityName);

        // Sign and replace the old certificate
        CertificateUtil.SignCertificate(certMan, csr, entityName);

        // Import the signed certificate
        KeyToolFacade.ImportCertificate(certMan, entityName,
                certMan.KEYSTORE_PATH + "/" + entityName + ".cer");
    }

    /**
     * Deletes the certificate and private key for the named entity
     * 
     * @param certMan
     * @param entityName -
     *            The entity whose keys are to be deleted
     */
    public static void DeleteCertificate(CertificateManager certMan,
            String entityName) {
        // Remove entry from Keystore
        KeyToolFacade.DeleteCertificate(certMan, entityName);

        // Remove .cer, .key, .csr files if any

        File f;
        f = new File(certMan.KEYSTORE_PATH + "/" + entityName + ".key");
        if (f.exists()) {
            if (f.delete())
                log.info("Deleted File:  " + f.getName());
        }

        f = new File(certMan.KEYSTORE_PATH + "/" + entityName + ".csr");
        if (f.exists()) {
            if (f.delete())
                log.info("Deleted File:  " + f.getName());
        }

        f = new File(certMan.KEYSTORE_PATH + "/" + entityName + ".cer");
        if (f.exists()) {
            if (f.delete())
                log.info("Deleted File:  " + f.getName());
        }
    }

    public static void main(String[] args) {
    // MUST INITIALIZE THE CertificateManager
    // CertificateManager.init(args[0]);

    // System.out.println("Issuing Signed Certificate ...");
    // ROOTSecurityProvider.IssueSignedCertificate("cgl-entity-2",
    // "\"CN=Entity-2,OU=Community Grids Lab,"
    // + "O=Indiana University,L=Bloomington,C=US\"", "30");
    // System.out.println("DONE !");

    // ROOT CERTIFICATE GENERATION..
    // ** USE ONLY ONCE **
    // System.out.println("Generating ROOT Certificates...");
    // ROOTSecurityProvider.GenerateROOTCertificate();
    // System.out.println("DONE !!");
    // ********************

    // Generating certificated for clients...
    // Preferably clean previous certificates

    // System.out.println("Cleaning previous Certs...");
    // ROOTSecurityProvider.DeleteCertificate("testuser");
    // System.out.println("Issuing Signed Certificate ...");
    // ROOTSecurityProvider.IssueSignedCertificate("testuser",
    // "\"CN=TestUser,OU=Community Grids Lab,"
    // + "O=Indiana University,L=Bloomington,C=US\"");
    // System.out.println("DONE !");

    // System.out.println("Cleaning previous Certs...");
    // ROOTSecurityProvider.DeleteCertificate("cgl-entity-1");
    // ROOTSecurityProvider.DeleteCertificate("tdn-1");
    // ROOTSecurityProvider.DeleteCertificate("tdc-1");
    //
    // System.out.println("Issuing Signed Certificate ...");
    // ROOTSecurityProvider.IssueSignedCertificate("cgl-entity-1",
    // "\"CN=CGL-Entity-1,OU=Community Grids Lab,"
    // + "O=Indiana University,L=Bloomington,C=US\"");
    //
    // ROOTSecurityProvider.IssueSignedCertificate("tdn-1",
    // "\"CN=TopicDiscoveryNode-1,OU=Community Grids Lab,"
    // + "O=Indiana University,L=Bloomington,C=US\"");
    //
    // ROOTSecurityProvider.IssueSignedCertificate("tdc-1",
    // "\"CN=TopicDiscoveryClient-1,OU=Community Grids Lab,"
    // + "O=Indiana University,L=Bloomington,C=US\"");
    //
    // System.out.println("DONE !");

    // Misc Test CASES !!

    // TEST CASE 1: Verify Certificates

    // String alias1 = "cgl-entity-a1";
    // String alias2 = "cgl-entity-a2";

    // ROOTSecurityProvider.IssueSignedCertificate(alias1, null);
    // ROOTSecurityProvider.IssueSignedCertificate(alias2, null);

    // PrivateKey priv1 = CertificateUtil.getPrivateKey(alias1);
    // PrivateKey priv2 = CertificateUtil.getPrivateKey(alias2);
    //
    // Certificate cert1 = CertificateUtil.getCertificate(alias1);
    // PublicKey pubKey1 = cert1.getPublicKey();
    //
    // Certificate cert2 = CertificateUtil.getCertificate(alias2);
    // PublicKey pubKey2 = cert2.getPublicKey();

    // PublicKey rootPubKey = CertificateUtil.getPublicKey("rootca");

    // try {
    // System.out.println("Verifying if CERT 1 was issued by ROOT");
    // cert1.verify(rootPubKey);
    // System.out.println("VALID !!");
    // } catch (Exception e2) {
    // log.error("INVALID: ", e2);
    // }
    //
    // try {
    // System.out.println("Verifying if CERT 2 was issued by CERT 1");
    // cert2.verify(pubKey1);
    // System.out.println("VALID !!");
    // } catch (Exception e2) {
    // log.error("INVALID: ", e2);
    // }
    //
    // TEST CASE 2: Encryption - Decryption test

    // try {
    // String xxx = "The Brown Fox jumped over the lazy dog";
    //
    // byte[] data = new byte[115];
    // for (int i = 0; i < data.length; i++)
    // data[i] = (byte) 'x';
    //
    // System.out.println("Encrypting: " + data.length + " bytes !");
    // EntityOperationsImpl entityOps = new EntityOperationsImpl();
    // // byte[] encrypted = entityOps.encryptPayload(pubKey1, data);
    //
    // Cipher cipher = Cipher.getInstance("RSA/CFB8/NoPadding");
    // cipher.init(Cipher.ENCRYPT_MODE, cert1.getPublicKey());
    // ByteArrayOutputStream bout = new ByteArrayOutputStream();
    // CipherOutputStream cout = new CipherOutputStream(bout, cipher);
    // cout.write(data);
    // cout.flush();
    // bout.flush();
    //
    // byte[] encrypted = bout.toByteArray(); // cipher.doFinal(data);
    //
    // System.out.println("Encrypted: " + encrypted.length);
    //
    // // Decrupt NOW
    // Cipher cipher2 = Cipher.getInstance("RSA/ECB/PKCS#1");
    // cipher2.init(Cipher.DECRYPT_MODE, priv1);
    //
    // ByteArrayInputStream bin = new ByteArrayInputStream(encrypted);
    // CipherInputStream cin = new CipherInputStream(bin, cipher2);
    //
    // ByteArrayOutputStream rcvd = new ByteArrayOutputStream();
    // byte[] buf = new byte[1024];
    // while (cin.available() > 0) {
    // int read = cin.read(buf);
    // rcvd.write(buf, 0, read);
    // }
    //
    // byte[] recievedData = rcvd.toByteArray(); //
    // entityOps.decryptPayload(priv1,
    // // encrypted);
    // System.out.println("(*1)Decrypting using correct PrivKey:\n RCVD: "
    // + recievedData.length + "\n" + new String(recievedData));
    //
    // // recievedData = entityOps.decryptPayload(priv2, encrypted);
    // // System.out.println("(*2)Decrypting using *INCORRECT* PrivKey:\n"
    // // + new String(recievedData));
    //
    // } catch (Exception e) {
    // log.error("", e);
    // }

    // ROOTSecurityProvider.DeleteCertificate(alias1);
    // ROOTSecurityProvider.DeleteCertificate(alias2);
    }
}
